package com.naiterui.ehp.bs.patient.handler;

import java.io.File;
import java.io.IOException;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import com.naiterui.common.redis.RedisUtil;
import com.naiterui.ehp.bp.bo.im.PatientMsgSendBO;
import com.naiterui.ehp.bp.bo.im.PatientMsgSendParamBO;
import com.naiterui.ehp.bp.constants.CommonConstant;
import com.naiterui.ehp.bp.constants.ImConstants;
import com.naiterui.ehp.bp.domain.Doctor;
import com.naiterui.ehp.bp.domain.Patient;
import com.naiterui.ehp.bp.domain.PatientPersonDoctor;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.utils.date.DateUtil;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bs.patient.bo.notice.UnPaidMsg;
import com.naiterui.ehp.bs.patient.constants.PatientJumperEnum;
import com.naiterui.ehp.bs.patient.dao.IDoctorDao;
import com.naiterui.ehp.bs.patient.dao.IPatientDao;
import com.naiterui.ehp.bs.patient.dao.IPatientPersonDoctorDao;
import com.naiterui.ehp.bs.patient.feign.EmrFeginClient;
import com.naiterui.ehp.bs.patient.feign.ImFeginClient;
import com.naiterui.ehp.bs.patient.handler.data.WxMsgEvent;
import com.naiterui.ehp.bs.patient.service.ITemplateNoticeService;
import com.naiterui.ehp.bs.wechat.service.ICustomMsgApiService;
import com.naiterui.ehp.bs.wechat.service.IMediaApiService;
import com.naiterui.ehp.bs.wechat.service.impl.WebAuthorizeApiServiceImpl;

import lombok.AllArgsConstructor;

/**
 * 微信用户
 * 主动消息发送事件处理
 *
 * @author gaoliangliang
 * @date 2019-07-12 14:27
 * @since 1.0.0
 */
@Component
@AllArgsConstructor
public class WxMsgHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(WxMsgHandler.class);

    private final ImFeginClient imFeginClient;
    private final IPatientDao patientDao;
    private final IDoctorDao doctorDao;
    private final IPatientPersonDoctorDao patientPersonDoctorDao;
    private final ICustomMsgApiService customMsgApiService;
    private final IMediaApiService mediaApiService;
    private final WebAuthorizeApiServiceImpl webAuthorizeApiServiceImpl;
    private final ITemplateNoticeService templateNoticeService;
    private final EmrFeginClient emrFeginClient;

    @Async
    @EventListener(classes = WxMsgEvent.class, condition = "#root.args[0].msgType == " + PatientMsgSendParamBO.MsgType.TEXT)
    public void wxMsgSend4Text(WxMsgEvent wxMsgEvent) {
        LOGGER.debug("文本消息");
        String openId = wxMsgEvent.getEventData().getOpenId();

        doSend(openId, false, PatientMsgSendParamBO.builder()
                                                 .msgType(wxMsgEvent.getMsgType())
                                                 .content(wxMsgEvent.getEventData().getContent())
                                                 .build());
    }

    @Async
    @EventListener(classes = WxMsgEvent.class, condition = "#root.args[0].msgType == " + PatientMsgSendParamBO.MsgType.IMAGE)
    public void wxMsgSend4Media(WxMsgEvent wxMsgEvent) throws IOException {
        LOGGER.debug("图片消息");
        String openId = wxMsgEvent.getEventData().getOpenId();

        // 存储图片、音频文件
        byte[] fileByte = mediaApiService.downloadTempMedia(wxMsgEvent.getEventData().getMediaId());
        String fileName = ConfigUtil.getString("im.image.root") + DateUtil.getCurrentCustomizeFormatDate(
                DateUtil.DATE_FORMAT_BY_DIAGONAL) + "/" + wxMsgEvent.getEventData().getMsgId() + ".jpg";
        File file = new File(fileName);
        FileUtils.forceMkdirParent(file);
        FileUtils.writeByteArrayToFile(file, fileByte);

        doSend(openId, false, PatientMsgSendParamBO.builder()
                                                 .msgType(wxMsgEvent.getMsgType())
                                                 .size(fileByte.length)
                                                 .path(fileName.replaceAll(ConfigUtil.getString("im.image.root"),
                                                                           ConfigUtil.getString("im.image.domain")))
                                                 .build());
    }

    @Async
    @EventListener(classes = WxMsgEvent.class, condition = "#root.args[0].msgType == " + PatientMsgSendParamBO.MsgType.VOICE)
    public void wxMsgSend4Voice(WxMsgEvent wxMsgEvent) throws IOException {
        LOGGER.debug("音频消息");
        String openId = wxMsgEvent.getEventData().getOpenId();

        // 存储音频文件
        byte[] fileByte = mediaApiService.downloadTempMedia(wxMsgEvent.getEventData().getMediaId());
        String fileName = ConfigUtil.getString("im.radio.root") + DateUtil.getCurrentCustomizeFormatDate(
                DateUtil.DATE_FORMAT_BY_DIAGONAL) + "/" + wxMsgEvent.getEventData().getMsgId() + ".amr";
        File file = new File(fileName);
        FileUtils.forceMkdirParent(file);
        FileUtils.writeByteArrayToFile(file, fileByte);

        doSend(openId, false, PatientMsgSendParamBO.builder()
                                                 .msgType(wxMsgEvent.getMsgType())
                                                 .content(wxMsgEvent.getEventData().getContent())
                                                 .path(fileName.replaceAll(ConfigUtil.getString("im.radio.root"),
                                                                           ConfigUtil.getString("im.radio.domain")))
                                                 .size(fileByte.length)
                                                 //音视频长度，使用JAVE处理
                                                 .timeLength(10)
                                                 .build());
    }

    @Async
    @EventListener(classes = WxMsgEvent.class,
            condition = "#root.args[0].msgType == " + PatientMsgSendParamBO.MsgType.VIDEO +
                    " || #root.args[0].msgType == " + PatientMsgSendParamBO.MsgType.SHORTVIDEO)
    public void wxMsgSend4Video(WxMsgEvent wxMsgEvent) throws IOException {
        LOGGER.debug("视频、小视频消息");
        String openId = wxMsgEvent.getEventData().getOpenId();

        // 存储视频、小视频文件
        byte[] fileByte = mediaApiService.downloadTempMedia(wxMsgEvent.getEventData().getMediaId());
        String fileName = ConfigUtil.getString("im.video.root") + DateUtil.getCurrentCustomizeFormatDate(
                DateUtil.DATE_FORMAT_BY_DIAGONAL) + "/" + wxMsgEvent.getEventData().getMsgId() + ".mp4";
        File file = new File(fileName);
        FileUtils.forceMkdirParent(file);
        FileUtils.writeByteArrayToFile(file, fileByte);

        doSend(openId, false, PatientMsgSendParamBO.builder()
                                                 .msgType(wxMsgEvent.getMsgType())
                                                 .content(wxMsgEvent.getEventData().getContent())
                                                 .path(fileName.replaceAll(ConfigUtil.getString("im.video.root"),
                                                                           ConfigUtil.getString("im.video.domain")))
                                                 .size(fileByte.length)
                                                 .build());
    }

    @Async
    @EventListener(classes = WxMsgEvent.class,
            condition = "#root.args[0].msgType == " + PatientMsgSendParamBO.MsgType.PATIENTDISEASE +
                    " || #root.args[0].msgType == " + PatientMsgSendParamBO.MsgType.MEDICALRECORD +
                    " || #root.args[0].msgType == " + PatientMsgSendParamBO.MsgType.CLINICFIRSTCONSULT)
    public void wxMsgSendPateintDisease(WxMsgEvent wxMsgEvent) {
        LOGGER.debug("医生已填写病历、患者病情消息");
        String openId = wxMsgEvent.getEventData().getOpenId();

        doSend(openId, true, PatientMsgSendParamBO.builder()
                                                 .msgType(wxMsgEvent.getMsgType())
                                                 .content(wxMsgEvent.getEventData().getContent())
                                                 .extId(wxMsgEvent.getEventData().getExtId())
                                                 .build());
    }


    //======================================================
    // 公共推送逻辑
    //======================================================
    private void doSend(String openId, boolean ignoreFlag, PatientMsgSendParamBO msgSendParamBO) {
        if (!ignoreFlag) {
            RedisUtil.valueOps().setString(CommonConstant.CONSULT_PATIENT_ACTIVE + openId, openId, 48 * 60 * 60);
        }

        Patient patient = patientDao.getPatientByOpenId(openId);

        // 客服电话
        if (patient == null || patient.getAccountStatus() != 0) {
            // 客服消息——>很抱歉，您的账户已被禁止使用。如需了解详情，如有疑问，请拨打${ehp_hospital_hotline}电话咨询，我们将竭诚为您服务
            customMsgApiService.sendSystemMsg(openId, "很抱歉，您的账户已被禁止使用。如需了解详情，如有疑问，请拨打" + ConfigUtil.getString("init.server.phone") + "电话咨询，我们将竭诚为您服务");
            return;
        }

        /*if (Patient.REAL_STATUS_SUCCESS != patient.getStatus()) {
            //患者未认证：客服消息——>您还未完善个人信息，点击完善(个人信息认证链接)
            customMsgApiService.sendSystemMsg(openId, "感谢您信任并使用" + ConfigUtil.getString("ehp.hospital.name") + "，线上问诊需实名认证，否则无法咨询医生，感谢您的配合。\n----------\n" +
                    webAuthorizeApiServiceImpl.getWebAuthorizeUrlSilent(ConfigUtil.getString("wechat.redirect.common.url"),
                                                                             PatientJumperEnum.PATIENT_AUTH.encodeWxParamStr(), "点击完成认证"));
            return;
        }*/

        Long doctorId;
        String doctorStr = RedisUtil.hashOps().hget(CommonConstant.CONSULT_PATIENT_AIM, patient.getId().toString());
        if (StringUtils.isNumeric(doctorStr)) {
            doctorId = Long.valueOf(doctorStr);
        } else {
            List<PatientPersonDoctor> patientDoctorList = patientPersonDoctorDao.getPersonPatientBindDoctor(patient.getId());
            if (patientDoctorList.size() <= 0) {
                // 无关联医生：客服消息——>抱歉，您的消息未能发送成功，请先扫描医生二维码吧。
                customMsgApiService.sendSystemMsg(openId, "抱歉，您的消息未能发送成功，请先扫描医生二维码吧。");
                return;
            } else if (patientDoctorList.size() > 1) {
                // 多个关联医生：客服消息——>请先选择您要咨询的医生(医生列表链接)
                customMsgApiService.sendSystemMsg(openId, "请先选择您要咨询的医生。" +
                        webAuthorizeApiServiceImpl.getWebAuthorizeUrlSilent(ConfigUtil.getString("wechat.redirect.common.url"),
                                                                                 PatientJumperEnum.DOCTOR_LIST.encodeWxParamStr(), "医生列表"));
                return;
            } else {
                // 一个关联医生：修改患者指向医生为该医生
                doctorId = patientDoctorList.get(0).getPersonPK().getDoctorId();
            }
        }

        // 医生账户状态
        Doctor doctor = doctorDao.get(doctorId);
        if (doctor == null) {
            // 客服消息——>无法获取医生信息，请联系客服
            customMsgApiService.sendSystemMsg(openId, "很抱歉，无法获取医生信息，请联系客服");
            return;
        } else if (doctor.getAccountStatus() == 1) {
            // 客服消息——>你关注的XXX医生已关闭在线问诊服务，如想进一步了解病情，请移步线下咨询！
            customMsgApiService.sendSystemMsg(openId, "您关注的" + doctor.getName() + "医生已关闭在线问诊服务，如想进一步了解病情，请移步线下咨询!");
            return;
        }

        try {
            msgSendParamBO.setDoctorId(doctorId);
            msgSendParamBO.setPatientId(patient.getId());
            String cacheInquirerId = RedisUtil.hashOps().hget(CommonConstant.CONSULT_PATIENT_AIM_INQUIRER, String.join("_" , doctorId.toString(), patient.getId().toString()));
            //校验免责协议声明，无则中断消息发送
            boolean disclaimer = RedisUtil.hashOps().hexist(CommonConstant.CONSULT_DISCLAIMER_ACTIVE, msgSendParamBO.getPatientId() + "_" + msgSendParamBO.getDoctorId());
            PatientPersonDoctor patientPersonDoctor = patientPersonDoctorDao.findByPatientIdAndDoctorId(patient.getId(), doctorId);
            if ((null != patientPersonDoctor && patientPersonDoctor.getRelationFlag().equals(PatientPersonDoctor.RELATION_FLAG_NORMALITY)) && StringUtils.isBlank(cacheInquirerId)) {
//                LOGGER.info("校验免责协议声明 session key:{}",CommonConstant.CONSULT_DISCLAIMER_ACTIVE + msgSendParamBO.getPatientId() + "_" + msgSendParamBO.getDoctorId());
//                LOGGER.info("患者是否同意免责协议开关: {}", !RedisUtil.keyOps().existsKey(CommonConstant.CONSULT_DISCLAIMER_SWITCH));
//                LOGGER.info("免责申请协议, {}", !disclaimer);
//                LOGGER.info("当前就诊医生信息, {}", cacheInquirerId);
//                customMsgApiService.sendSystemMsg(patient.getOpenId(),
//                            String.format(ConfigKeyUtil.getString("wachat.sysmsg.disclaimer"), doctor.getName(),
//                                webAuthorizeApiServiceImpl.getWebAuthorizeUrlSilent(ConfigUtil.getString("wechat.redirect.common.url"),
//                                    PatientJumperEnum.PATIENT_MEDICAL_RECORD_LIST.encodeWxParamStr(doctorId.toString()), "点击选择就诊人或者添加就诊人")));
                return;
            }

            if (null != cacheInquirerId) {
                msgSendParamBO.setInquirerId(Long.parseLong(cacheInquirerId));
            }

            PatientMsgSendBO patientMsgSendBO = imFeginClient.wxMessageSend(msgSendParamBO);
            LOGGER.info("微信主动消息推送IM结果：{}",patientMsgSendBO);
            if (patientMsgSendBO.getResult()) {
                // 发送病情后的系统通知
                if(msgSendParamBO.getMsgType() == PatientMsgSendParamBO.MsgType.PATIENTDISEASE){
                    LOGGER.info("发送病情后的系统通知");
                    PatientMsgSendParamBO patientMsgSendParamBO = new PatientMsgSendParamBO();
                    patientMsgSendParamBO.setMsgType(ImConstants.MESSAGE_TYPE_PATIENTS_DISEASE);
                    patientMsgSendParamBO.setDoctorId(msgSendParamBO.getDoctorId());
                    patientMsgSendParamBO.setPatientId(msgSendParamBO.getPatientId());
                    patientMsgSendParamBO.setInquirerId(msgSendParamBO.getInquirerId());
                    patientMsgSendParamBO.setContent("您的病情已发送给医生，请耐心等待医生回复");
                    imFeginClient.sendPatientSysMessage(patientMsgSendParamBO);
                }
                if (patientMsgSendBO.getFirst()) {
                    // isFirst当天首条信息，文字小于30、图片、音频：客服消息——>您的消息已发送给XXX医生，完整病历信息有助医生更好诊断，请继续描述您的不适症状，医生将利用空闲时间为您服务。医生信息(医生详情链接)
                    customMsgApiService.sendSystemMsg(openId, "消息已成功送达" + doctor.getName() + "医生。医生可能不能及时回复，请继续将症状和问题描述完整，便于医生分析诊断~\n----------\n" +
                            webAuthorizeApiServiceImpl.getWebAuthorizeUrlSilent(ConfigUtil.getString("wechat.redirect.common.url"),
                                                                                     PatientJumperEnum.DOCTOR_DETAIL.encodeWxParamStr(doctorId.toString()),"医生信息"));
                }
                // 发送成功-患者病情描述更新sessionId创建关联关系
                if (PatientMsgSendParamBO.MsgType.PATIENTDISEASE == msgSendParamBO.getMsgType()) {
                    String recordId = msgSendParamBO.getExtId();
                    String sessionId = patientMsgSendBO.getSessionId();
                    emrFeginClient.caseSessionBind(recordId, sessionId);
                }

            } else {
                if (patientMsgSendBO.getClosed()) {
                    //endTime，结束会话：客服消息——>当前会话已经结束，请选择医生开启新会话！
                    customMsgApiService.sendSystemMsg(openId, "当前会话已经结束，请选择医生开启新会话！");
                }else{
                    if (StringUtils.isNumeric(patientMsgSendBO.getConsultPrice()) && Integer.parseInt(patientMsgSendBO.getConsultPrice()) > 0) {
                        // 模板消息——>付费咨询 您好！{$dinfo['name']}医生已开通图文咨询付费服务，立即升级，即可发送图文、语音与{$dinfo['name']}医生咨询，不用去医院排队挂号即可咨询，答疑解惑更方便。
                        UnPaidMsg unPaidMsg = UnPaidMsg.builder().consultPrice(String.valueOf(Integer.parseInt(patientMsgSendBO.getConsultPrice()) / 100)).doctorName(doctor.getName()).build();
                        unPaidMsg.setOpenId(openId);
                        unPaidMsg.setTargetPage(webAuthorizeApiServiceImpl.getWebAuthorizeUrlSilent(
                                ConfigUtil.getString("wechat.redirect.common.url"),
                                PatientJumperEnum.PAY_CONSULT.encodeWxParamStr(doctorId.toString())));
                        templateNoticeService.notice(unPaidMsg);
                    }
                }
            }
        } catch (BusinessException e) {
            // 客服消息——>异常信息
            customMsgApiService.sendSystemMsg(openId, e.getMessage());
            LOGGER.error("患者用户，主动发送消息失败，openId={},error={}", openId, e.getMessage());
        }
    }

}
